﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace H.Utils
{
    /// <summary>
    /// 延时工具类
    /// </summary>
    public static class DelayUtil
    {
        /// <summary>
        /// 内部使用的随机数产生器
        /// </summary>
        private static readonly Random Random = new Random();

        /// <summary>
        /// 延时n ms,用于对准确性要求非常高的场合,但此延时函数只能用于100ms以上的延时,
        /// </summary>
        /// <param name="ms">目标延时时长</param>
        /// <returns>实际的延时时长</returns>
        public static int Delay(int ms)
        {
            long start = DateTime.Now.Ticks;
            long end = start + ms * 10000;

            if (end - DateTime.Now.Ticks > 500000)
            {
                Thread.Sleep((int)((end - DateTime.Now.Ticks) / 10000) - 50);
            }

            while (end - DateTime.Now.Ticks > 100)
            {
                Thread.SpinWait(100);
            }
            return (int)((DateTime.Now.Ticks - start) / 10000);
        }

        /// <summary>
        /// 随机延时min~max毫秒(适用于对准确性要求不高的场合或者需要刻意随机延时的场合)
        /// </summary>
        /// <param name="min">最短延时时间</param>
        /// <param name="max">最长延时时间</param>
        /// <returns>返回真实延时时间(ms)</returns>
        public static int Delay(int min, int max)
        {
            long start = DateTime.Now.Ticks;
            long end = start + min * 10000;
            end += Random.Next((max - min) * 10000);
            if (end - DateTime.Now.Ticks > 500000)
            {
                Thread.Sleep((int)((end - DateTime.Now.Ticks) / 10000) - 50);
            }

            while (end - DateTime.Now.Ticks > 100)
            {
                Thread.SpinWait(100);
            }
            return (int)((DateTime.Now.Ticks - start) / 10000);
        }

        /// <summary>
        /// 延时n ms,用于对准确性要求非常高的场合,同时对ct进行响应
        /// </summary>
        /// <param name="ms">目标延时毫秒数</param>
        /// <param name="ct">停止计时的令牌</param>
        /// <returns>当通过ct强行停止时,返回值为-1,否则为实际的延时时长</returns>
        public static int Delay(int ms, CancellationToken ct)
        {
            long start = DateTime.Now.Ticks;
            long end = start + ms * 10000;

            if (end - DateTime.Now.Ticks > 5000000)
            {
                if (ct.IsCancellationRequested)
                {
                    return -1;
                }
                Thread.Sleep(450);
            }

            while (end - DateTime.Now.Ticks > 100)
            {
                Thread.SpinWait(100);
            }
            return (int)((DateTime.Now.Ticks - start) / 10000);
        }

        /// <summary>
        /// 随机延时min~max毫秒(可能会有40ms的误差,适用于对准确性要求不高的场合)
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns>当通过ct强行停止时,返回值为-1,否则为实际的延时时长</returns>
        public static int Delay(int min, int max, CancellationToken ct)
        {
            long start = DateTime.Now.Ticks;
            long end = start + min * 10000;
            end += Random.Next((max - min) * 10000);
            while (end - DateTime.Now.Ticks > 5000000)
            {
                if (ct.IsCancellationRequested)
                {
                    return -1;
                }
                Thread.Sleep(450);
            }

            while (end - DateTime.Now.Ticks > 100)
            {
                Thread.SpinWait(100);
            }
            return (int)((DateTime.Now.Ticks - start) / 10000);
        }
    }
}
